package com.chianghao.qyt.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chianghao.qyt.auth.LoginUser;
import com.chianghao.qyt.entity.SysOperationAdmin;
import com.chianghao.qyt.entity.SysOperationAdminRole;
import com.chianghao.qyt.entity.SysOperationRole;
import com.chianghao.qyt.i18n.SysOperationLanguage;
import com.chianghao.qyt.mapper.SysOperationAdminMapper;
import com.chianghao.qyt.mapper.SysOperationAdminRoleMapper;
import com.chianghao.qyt.mapper.SysOperationRoleMapper;
import com.chianghao.qyt.service.SysOperationAdminService;
import com.chianghao.frame.core.auth.ClientTypeEnum;
import com.chianghao.frame.core.auth.Login;
import com.chianghao.frame.core.auth.jwt.JwtEntityDefault;
import com.chianghao.frame.core.exception.CHLanguageException;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SysOperationAdminServiceImpl implements SysOperationAdminService {


    @Resource
    SysOperationAdminMapper sysOperationAdminMapper;

    @Resource
    SysOperationAdminRoleMapper sysOperationAdminRoleMapper;

    @Resource
    SysOperationRoleMapper sysOperationRoleMapper;

    @Resource
    PasswordEncoder passwordEncoder;

    @Resource
    Login mesageLogin;

    Logger log  = LoggerFactory.getLogger(this.getClass());


    @Override
    public void logout(Long userId) {
        mesageLogin.logoutByUserId(userId.toString());
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void modifyPassword(Long userId, String oldPassword, String newPassword, String newPasswordConfirm) {
        if (!newPassword.equals(newPasswordConfirm)) {
            throw new CHLanguageException(SysOperationLanguage.TWO_PASSWORD_NOT_EQUALS);
        }
        SysOperationAdmin sysOperationAdmin = this.sysOperationAdminMapper.selectById(userId);
        if (sysOperationAdmin == null) {
            throw new CHLanguageException(SysOperationLanguage.ACCOUNT_NOT_EXIST);
        }
        if (!passwordEncoder.matches(oldPassword, sysOperationAdmin.getPassword())) {
            throw new CHLanguageException(SysOperationLanguage.OLD_PASSWORD_ERROR);
        }
        new LambdaUpdateChainWrapper<SysOperationAdmin>(this.sysOperationAdminMapper)
                .set(SysOperationAdmin::getPassword, passwordEncoder.encode(newPassword))
                .eq(SysOperationAdmin::getId, userId)
                .update();
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void addAdmin(String account, String username, String password) {
        long count = this.sysOperationAdminMapper.selectCount(new QueryWrapper<SysOperationAdmin>().lambda()
                .eq(SysOperationAdmin::getAccount, account));
        if(count>0){
            throw new CHLanguageException(SysOperationLanguage.ACCOUNT_EXIST);
        }
        SysOperationAdmin admin = new SysOperationAdmin();
        admin.setAccount(account);
        admin.setPassword(passwordEncoder.encode(password));
        admin.setSuperAdmin(false);
        admin.setUserName(username);
        this.sysOperationAdminMapper.insert(admin);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void modifyAdmin(Long id, String account, String username) {
        if(StringUtils.isBlank(account) && StringUtils.isBlank(username)){
            log.error("修改账号时姓名和账号同时为空，这种情况不能修改账号！");
            return;
        }
        long count = this.sysOperationAdminMapper.selectCount(new QueryWrapper<SysOperationAdmin>().lambda()
                .eq(SysOperationAdmin::getAccount, account)
                .ne(SysOperationAdmin::getId,id)
        );
        if(count>0){
            throw new CHLanguageException(SysOperationLanguage.ACCOUNT_EXIST);
        }
        new LambdaUpdateChainWrapper<SysOperationAdmin>(this.sysOperationAdminMapper)
                .eq(SysOperationAdmin::getId,id)
                .set(StringUtils.isNoneBlank(account),SysOperationAdmin::getAccount, account)
                .set(StringUtils.isNoneBlank(account),SysOperationAdmin::getUserName, username)
                .update();

    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void modifyAdminPassword(Long id, String password) {
        if(StringUtils.isBlank(password)){
            log.error("修改密码是参数为空");
            throw new CHLanguageException(SysOperationLanguage.PARAM_NULL);
        }
        new LambdaUpdateChainWrapper<SysOperationAdmin>(this.sysOperationAdminMapper)
                .eq(SysOperationAdmin::getId,id)
                .set(SysOperationAdmin::getPassword,passwordEncoder.encode(password))
                .update();
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void delete(Long id) {
        this.sysOperationAdminMapper.deleteById(id);
        this.sysOperationAdminRoleMapper.delete(new QueryWrapper<SysOperationAdminRole>().lambda()
                .eq(SysOperationAdminRole::getAdminId,id));
    }



    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void setSysOperationRole(Long accountId, HashSet<Long> roleIds) {
        // 先删除
        this.sysOperationAdminRoleMapper.delete(new QueryWrapper<SysOperationAdminRole>().lambda().eq(SysOperationAdminRole::getAdminId,accountId));
        // 后添加
        if(roleIds!=null && !roleIds.isEmpty()){
            this.sysOperationAdminRoleMapper.insertBatch(roleIds.stream().map(i->{
                SysOperationAdminRole soar = new SysOperationAdminRole();;
                soar.setAdminId(accountId);
                soar.setRoleId(i);
                return soar;
            }).toList());
        }
    }

    @Override
    public Map<Long, List<SysOperationRole>> selectAccountRoleMap(Set<Long> sysOperationAccountIds) {
        if(sysOperationAccountIds==null || sysOperationAccountIds.isEmpty()){
            return Collections.emptyMap();
        }
        List<SysOperationAdminRole> adminRoles =
                this.sysOperationAdminRoleMapper.selectList(new QueryWrapper<SysOperationAdminRole>().lambda()
                        .in(SysOperationAdminRole::getAdminId, sysOperationAccountIds));

        if(adminRoles==null||adminRoles.isEmpty()){
            return Collections.emptyMap();
        }

        Map<Long,List<SysOperationAdminRole>> map = adminRoles.stream()
                .collect(Collectors.groupingBy(SysOperationAdminRole::getAdminId));


        List<SysOperationRole> roles = sysOperationRoleMapper.selectList(
                new QueryWrapper<SysOperationRole>().lambda()
                        .in(SysOperationRole::getId,
                                adminRoles.stream().map(SysOperationAdminRole::getRoleId)
                                .collect(Collectors.toSet()))
        );
        Map<Long,SysOperationRole> roleMap = roles.stream().collect(Collectors.toMap(SysOperationRole::getId,m->m,(a,b)->a));

        Map<Long,List<SysOperationRole>> result = new HashMap<>();
        for(Map.Entry<Long,List<SysOperationAdminRole>> entry:map.entrySet()){
            List<SysOperationRole> tempList = result.computeIfAbsent(entry.getKey(), k -> new ArrayList<>());
            for(SysOperationAdminRole o:entry.getValue()){
                tempList.add(roleMap.get(o.getRoleId()));
            }
        }
        return result;
    }

    @Override
    public boolean isSupperAdmin(Long userId) {
        SysOperationAdmin admin = this.sysOperationAdminMapper
                .selectOne(new QueryWrapper<SysOperationAdmin>().lambda()
                        .eq(SysOperationAdmin::getId,userId)
                        .select(SysOperationAdmin::getSuperAdmin,SysOperationAdmin::getId)
                );

        return admin != null && (admin.getSuperAdmin());
    }


    @Override
    public String login(String sessionId, String account, String password) {
        if (StringUtils.isBlank(account)) {
            throw new CHLanguageException(SysOperationLanguage.PARAM_ACCOUNT_NULL);
        }
        if (StringUtils.isBlank(password)) {
            throw new CHLanguageException(SysOperationLanguage.PARAM_PASSWORD_NULL);
        }
        SysOperationAdmin admin = this.sysOperationAdminMapper.selectOne(new QueryWrapper<SysOperationAdmin>().lambda().eq(SysOperationAdmin::getAccount, account));
        if (admin == null) {
            throw new CHLanguageException(SysOperationLanguage.ACCOUNT_NOT_EXIST);
        }
        if (!passwordEncoder.matches(password, admin.getPassword())) {
            throw new CHLanguageException(SysOperationLanguage.PASSWORD_ERROR);
        }

        JwtEntityDefault jwtEntity = new JwtEntityDefault();
        jwtEntity.setUserId(admin.getId().toString());
        jwtEntity.setClientType(ClientTypeEnum.BROWSER);
        String token = mesageLogin.login(sessionId, jwtEntity, ClientTypeEnum.BROWSER, null);

        LoginUser loginUserInfo = new LoginUser();
        loginUserInfo.setUserId(admin.getId());
        loginUserInfo.setUserName(admin.getUserName());
        loginUserInfo.setAccount(admin.getAccount());
        loginUserInfo.setRoles(null);
        loginUserInfo.setSuperAdmin(admin.getSuperAdmin());
        loginUserInfo.setDataIds(null);
        mesageLogin.setUser(sessionId, loginUserInfo);
        return token;
    }

    @Override
    public SysOperationAdmin queryById(Long adminId) {
        return this.sysOperationAdminMapper.selectById(adminId);
    }

    @Override
    public IPage<SysOperationAdmin> queryPage(Long userId, int pageIndex, int pageSize) {
        return this.sysOperationAdminMapper.selectPage(new Page<SysOperationAdmin>(pageIndex, pageSize),
                new QueryWrapper<SysOperationAdmin>().lambda()
                        .ne(SysOperationAdmin::getId, userId)
                        .eq(SysOperationAdmin::getSuperAdmin, false)
        );
    }


}
